##
## Report.py 
##
## Generate PDF reports with the reportlab pdf library
##
## Author: Shannon Eric Peevey <speeves@erikin.com>, 12/11/2006
##

from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import A4, letter
import os, sys, re, ldap
from datetime import date
import Ldap

#find out what platform we are on and whether accelerator is
#present, in order to print this as part of benchmark info.
try:
    import _rl_accel
    ACCEL = 1
except ImportError:
    ACCEL = 0


class ReportFunc:
    """ Comment about the Class """
	
    def __init__(self, pagesize="letter"):
        """ calculate basic document definitions """
        #precalculate some basics
        if pagesize == "letter":
            self.pagesize = letter
        else:
            self.pagesize = A4

        self.top_margin = self.pagesize[1] - inch
        self.right_margin = self.pagesize[0] - inch
        self.bottom_margin = inch
        self.left_margin = inch
        self.frame_width = self.right_margin - self.left_margin

        
    def DrawPageFrame(self, canv, title):
        canv.line(self.left_margin, self.top_margin, self.right_margin, self.top_margin)
        canv.setFont('Times-Italic',12)
        canv.drawString(self.left_margin, self.top_margin + 2, title)
        canv.line(self.left_margin, self.top_margin, self.right_margin, self.top_margin)


        canv.line(self.left_margin, self.bottom_margin, self.right_margin, self.bottom_margin)
        canv.drawCentredString(0.5*self.pagesize[0], 0.5 * inch,
               "Page %d" % canv.getPageNumber())


    def Run(self, title, department, header, data, outputfile, verbose=1):
        canv = canvas.Canvas(outputfile, invariant=1)
        canv.setPageCompression(1)
        self.DrawPageFrame(canv, title)

        #do some title page stuff
        canv.setFont("Times-Bold", 36)
        canv.drawCentredString(0.5 * self.pagesize[0], 7 * inch, title)

        canv.setFont("Times-Bold", 18)
        canv.drawCentredString(0.5 * self.pagesize[0], 5 * inch, department)
        d = date.today()
        canv.drawCentredString(0.5 * self.pagesize[0], 4.5 * inch, str(d.month) + "/" + str(d.day) + "/" + str(d.year))

        canv.showPage()
        #on with the text...
        self.DrawPageFrame(canv, title)

        canv.setFont('Times-Roman', 12)
        tx = canv.beginText(self.left_margin, self.top_margin - 0.5*inch)

        # call the appropriate report type
        self.ThreeColumnReport(canv, tx, header, data)
        
        if tx:
            canv.drawText(tx)
            canv.showPage()
            self.DrawPageFrame(canv, title)

        if verbose:
            print 'about to write to disk...'

        canv.save()


    def ThreeColumnReport(self, canv, tx, header, data):
        """ print out a three column report in portrait view """
        # this is optimized for portrait, not landscape
        tx.textLine(header)
        canv.line(self.left_margin, self.top_margin - 0.55*inch, self.right_margin-2*inch, self.top_margin - 0.55*inch)

        for line in data[0]:
            newLine = line
            if type(newLine) == list:
                spacer = " "*37
                text = spacer
                for i in newLine:
                    text = text + "| " + i + " "*(30 - (len(i)/2))
                tx.textLine(text)
            else:
                tx.textLine(newLine)
            canv.drawText(tx)

            self.PageBreakingAndFooter(canv, tx, title)


    def LdapSearchPrintFormatPDF(self, config, utilityObject, filterDict, filter, dn="", attr={}, outputfile="/tmp/ldapreport.pdf", verbose=1): 
        """ Print out the results of the LDAP Search into a PDF format """

        print "We are now going to generate a PDF version or our LDAP search results"
        print
        print "First, we will need to gather some information for the report"
        print
        title = raw_input("Report Title? [Test Report] ")
        if title == "":
            title = "Test Report"
        department = raw_input("Department? [My Department] ")
        if department == "":
            department = "My Department"

        canv = canvas.Canvas(outputfile, invariant=1)
        canv.setPageCompression(1)
        self.DrawPageFrame(canv, title)

        #do some title page stuff
        canv.setFont("Times-Bold", 36)
        canv.drawCentredString(0.5 * self.pagesize[0], 7 * inch, title)

        canv.setFont("Times-Bold", 18)
        canv.drawCentredString(0.5 * self.pagesize[0], 5 * inch, department)
        d = date.today()
        canv.drawCentredString(0.5 * self.pagesize[0], 4.5 * inch, str(d.month) + "/" + str(d.day) + "/" + str(d.year))

        canv.showPage()
        #on with the text...
        self.DrawPageFrame(canv, title)

        canv.setFont('Times-Roman', 12)
        tx = canv.beginText(self.left_margin, self.top_margin - 0.5*inch)
        
        tx.textLine("filter is " + filter)

        ## DEBUGGING
        if config['General']["debugLevel"] == '1':
            print "filterDict == ", filterDict
            print "dn == ", dn
            print "attr == ", attr

        x = 0
        if len(filterDict) == 2 and type(filterDict) is tuple:
            ## DEBUGGING
            if config['General']["debugLevel"] == '1':
                print "dn == ", dn
                print "attr == ", attr

            tx.textLine("---------------------")
            tx.textLine("")
            tx.textLine("dn: " + dn)
            tx.textLine("")

            # don't touch formatting, as I don't understand why these seem to work
            # in the pdf
            if attr.has_key('cn'):
                tx.textLine("                                    cn: %s" % attr['cn'])
            if attr.has_key('givenName'):
                tx.textLine("                     givenName: %s" % attr['givenName'])
            if attr.has_key('mi'):
                tx.textLine("                       mi: %s" % attr['mi'])
            if attr.has_key('sn'):
                tx.textLine("                                    sn: %s" % attr['sn'])
            if attr.has_key('euid'):
                tx.textLine("                     euid: %s" % attr['euid'])
            if attr.has_key('uid'):
                tx.textLine("                                   uid: %s" % attr['uid'])
            if attr.has_key('idno'):
                tx.textLine("                     idno: %s" % attr['idno'])
            if attr.has_key('college'):
                tx.textLine("                  college: %s" % attr['college'])
            if attr.has_key('role'):
                tx.textLine("                     role: %s" % attr['role'])
            if attr.has_key('birthdate'):
                tx.textLine("                birthdate: %s" % attr['birthdate'])
            # epSite object attributes
            if attr.has_key('siteStatus'):
                tx.textLine("                         Site Live: %s" % attr['siteStatus'])
            if attr.has_key('url'):
                tx.textLine("                         Site URL: %s" % attr['url'])
            if attr.has_key('progLang'):
                tx.textLine("Programming Languages: %s" % attr['progLang'])
            # epForm object attributes
            if attr.has_key('directoryInfo'):
                tx.textLine("    Directory Information: %s" % attr['directoryInfo'])
            if attr.has_key('formMember'):
                tx.textLine("            Web Form Name: %s" % attr['formMember'])
            if attr.has_key('formPurpose'):
                tx.textLine("    Purpose of Web Form: %s" % attr['formPurpose'])
            if attr.has_key('privPolicy'):
                tx.textLine("Is there a privacy policy? %s" % attr['privPolicy'])
            if attr.has_key('recordRetention'):
                tx.textLine("               Data Retention? %s days" % attr['recordRetention'])
            if attr.has_key('registeredBy'):
                tx.textLine("                Registered By? %s " % attr['registeredBy'])
            
            if attr.has_key('member'):
                euidList = []
                for euid in attr['member']:
                    splitEuid = re.split(',', euid)
                    euidFilter = splitEuid[0]
                    euidList.append(euidFilter)
                    ## this is causing a lot of extra calls to ldap and slowing long printouts to stdout
                    ## need to do a single connect here, instead of multiple connections
                    l = Ldap.LdapFunc()
                    ## DEBUGGING
                    if config['General']["debugLevel"] == '5':
                        print "euidFilter == ", euidFilter
                    euidDict = l.LdapSearch(config, euidFilter)
                    name = ''
                    ## DEBUGGING
                    if config['General']["debugLevel"] == '5':
                        print "euidDict == ", euidDict

                    if euidDict != None:
                        for euidAttr in euidDict:
                            key = euidAttr[0]
                            value = euidAttr[1]

                            if value.has_key('givenName'):
                                name = value['givenName']
                            if value.has_key('sn'):
                                name = name + value['sn']
                                tx.textLine(" "*27 + "member: %s" % name)

                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "member: %s" % attr['member']
                    print "len(euidList) == ", len(euidList)
                if len(euidList) > 0:
                    for euid in euidList:
                        ## DEBUGGING
                        if config['General']["debugLevel"] == '5':
                            print "euid == ", euid
                        if euid != "":
                            splitEuid2 = re.split('=', euid)
                            tx.textLine(" "*33 + "euid: %s" % splitEuid2[1])

            tx.textLine("---------------------")
            tx.textLine("")

            #page breaking
            y = tx.getY()   #get y coordinate
            if y < self.bottom_margin + 0.5*inch:
                canv.drawText(tx)
                canv.showPage()
                self.DrawPageFrame(canv, title)
                canv.setFont('Times-Roman', 12)
                tx = canv.beginText(self.left_margin, self.top_margin - 0.5*inch)

            #page
            pg = canv.getPageNumber()
            if verbose and pg % 10 == 0:
                print 'formatted page %d' % canv.getPageNumber()

        else:
            for name in filterDict:
                dn = name[0]
                attr = name[1]

                ## DEBUGGING
                if config['General']["debugLevel"] == '1':
                    #print "filterDict == ", filterDict
                    print "dn == ", dn
                    print "attr == ", attr

                

                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "dn == ", dn
                    print "attr == ", attr

                tx.textLine("---------------------")
                tx.textLine("")
                tx.textLine("dn: " + dn)
                tx.textLine("")

                # don't touch formatting, as I don't understand why these seem to work
                # in the pdf
                if attr.has_key('cn'):
                    tx.textLine("                                    cn: %s" % attr['cn'])
                if attr.has_key('givenName'):
                    tx.textLine("                     givenName: %s" % attr['givenName'])
                if attr.has_key('mi'):
                    tx.textLine("                       mi: %s" % attr['mi'])
                if attr.has_key('sn'):
                    tx.textLine("                                    sn: %s" % attr['sn'])
                if attr.has_key('euid'):
                    tx.textLine("                     euid: %s" % attr['euid'])
                if attr.has_key('uid'):
                    tx.textLine("                                   uid: %s" % attr['uid'])
                if attr.has_key('idno'):
                    tx.textLine("                     idno: %s" % attr['idno'])
                if attr.has_key('college'):
                    tx.textLine("                  college: %s" % attr['college'])
                if attr.has_key('role'):
                    tx.textLine("                     role: %s" % attr['role'])
                if attr.has_key('birthdate'):
                    tx.textLine("                birthdate: %s" % attr['birthdate'])
                # epSite object attributes
                if attr.has_key('siteStatus'):
                    tx.textLine("                         Site Live: %s" % attr['siteStatus'])
                if attr.has_key('url'):
                    tx.textLine("                         Site URL: %s" % attr['url'])
                if attr.has_key('progLang'):
                    tx.textLine("Programming Languages: %s" % attr['progLang'])
                # epForm object attributes
                if attr.has_key('directoryInfo'):
                    tx.textLine("    Directory Information: %s" % attr['directoryInfo'])
                if attr.has_key('formMember'):
                    tx.textLine("            Web Form Name: %s" % attr['formMember'])
                if attr.has_key('formPurpose'):
                    tx.textLine("    Purpose of Web Form: %s" % attr['formPurpose'])
                if attr.has_key('privPolicy'):
                    tx.textLine("Is there a privacy policy? %s" % attr['privPolicy'])
                if attr.has_key('recordRetention'):
                    tx.textLine("               Data Retention? %s days" % attr['recordRetention'])
                if attr.has_key('registeredBy'):
                    tx.textLine("                Registered By? %s " % attr['registeredBy'])
            
                if attr.has_key('member'):
                    euidList = []
                    for euid in attr['member']:
                        splitEuid = re.split(',', euid)
                        euidFilter = splitEuid[0]
                        euidList.append(euidFilter)
                        ## this is causing a lot of extra calls to ldap and slowing long printouts to stdout
                        ## need to do a single connect here, instead of multiple connections
                        l = Ldap.LdapFunc()
                        euidDict = l.LdapSearch(config, euidFilter)
                        name = ''
                        ## DEBUGGING
                        if config['General']["debugLevel"] == '5':
                            print "euidDict == ", euidDict

                        if euidDict != None:
                            for euidAttr in euidDict:
                                key = euidAttr[0]
                                value = euidAttr[1]

                                if value.has_key('givenName'):
                                    name = value['givenName']
                                if value.has_key('sn'):
                                    name = name + value['sn']
                                    tx.textLine(" "*27 + "member: %s" % name)

                    ## DEBUGGING
                    if config['General']["debugLevel"] == '5':
                        print "member: %s" % attr['member']
                        print "len(euidList) == ", len(euidList)
                    if len(euidList) > 0:
                        for euid in euidList:
                            ## DEBUGGING
                            if config['General']["debugLevel"] == '5':
                                print "euid == ", euid
                            if euid != "":
                                splitEuid2 = re.split('=', euid)
                                tx.textLine(" "*33 + "euid: %s" % splitEuid2[1])

                tx.textLine("---------------------")
                tx.textLine("")

                #page breaking
                y = tx.getY()   #get y coordinate
                if y < self.bottom_margin + 0.5*inch:
                    canv.drawText(tx)
                    canv.showPage()
                    self.DrawPageFrame(canv, title)
                    canv.setFont('Times-Roman', 12)
                    tx = canv.beginText(self.left_margin, self.top_margin - 0.5*inch)

                #page
                pg = canv.getPageNumber()
                if verbose and pg % 10 == 0:
                    print 'formatted page %d' % canv.getPageNumber()

        if tx:
            canv.drawText(tx)
            canv.showPage()
            self.DrawPageFrame(canv, title)

        #    canv.showPage()
        #    self.DrawPageFrame(canv, title)

        if verbose:
            print 'about to write to disk...'

        canv.save()

        self.SendEmail(config, title, department, outputfile)


    def LdapSearchGeneratePDFBody(self, config, canv, tx, title, dn, attr):
        """ Generate the actual body of the PDF file from the contents
            of the Ldap Search.
            - filterDict is split into the string dn
            - and the dict attr
            """
        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "dn == ", dn
            print "attr == ", attr

        tx.textLine("---------------------")
        tx.textLine("")
        tx.textLine("dn: " + dn)
        tx.textLine("")

        # don't touch formatting, as I don't understand why these seem to work
        # in the pdf
        if attr.has_key('cn'):
            tx.textLine("                                    cn: %s" % attr['cn'])
        if attr.has_key('givenName'):
            tx.textLine("                     givenName: %s" % attr['givenName'])
        if attr.has_key('mi'):
            tx.textLine("                       mi: %s" % attr['mi'])
        if attr.has_key('sn'):
            tx.textLine("                                    sn: %s" % attr['sn'])
        if attr.has_key('euid'):
            tx.textLine("                     euid: %s" % attr['euid'])
        if attr.has_key('uid'):
            tx.textLine("                                   uid: %s" % attr['uid'])
        if attr.has_key('idno'):
            tx.textLine("                     idno: %s" % attr['idno'])
        if attr.has_key('college'):
            tx.textLine("                  college: %s" % attr['college'])
        if attr.has_key('role'):
            tx.textLine("                     role: %s" % attr['role'])
        if attr.has_key('birthdate'):
            tx.textLine("                birthdate: %s" % attr['birthdate'])
        # epSite object attributes
        if attr.has_key('siteStatus'):
            tx.textLine("                         Site Live: %s" % attr['siteStatus'])
        if attr.has_key('url'):
            tx.textLine("                         Site URL: %s" % attr['url'])
        if attr.has_key('progLang'):
            tx.textLine("Programming Languages: %s" % attr['progLang'])
        # epForm object attributes
        if attr.has_key('directoryInfo'):
            tx.textLine("    Directory Information: %s" % attr['directoryInfo'])
        if attr.has_key('formMember'):
            tx.textLine("            Web Form Name: %s" % attr['formMember'])
        if attr.has_key('formPurpose'):
            tx.textLine("    Purpose of Web Form: %s" % attr['formPurpose'])
        if attr.has_key('privPolicy'):
            tx.textLine("Is there a privacy policy? %s" % attr['privPolicy'])
        if attr.has_key('recordRetention'):
            tx.textLine("               Data Retention? %s days" % attr['recordRetention'])
        if attr.has_key('registeredBy'):
            tx.textLine("                Registered By? %s " % attr['registeredBy'])
            
        if attr.has_key('member'):
            euidList = []
            for euid in attr['member']:
                splitEuid = re.split(',', euid)
                euidFilter = splitEuid[0]
                euidList.append(euidFilter)
                ## this is causing a lot of extra calls to ldap and slowing long printouts to stdout
                ## need to do a single connect here, instead of multiple connections
                l = Ldap.LdapFunc()
                euidDict = l.LdapSearch(config, euidFilter)
                name = ''
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "euidDict == ", euidDict

                for euidAttr in euidDict:
                    key = euidAttr[0]
                    value = euidAttr[1]

                    if value.has_key('givenName'):
                        name = value['givenName']
                    if value.has_key('sn'):
                        name = name + value['sn']
                        tx.textLine(" "*27 + "member: %s" % name)

            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "member: %s" % attr['member']
                print "len(euidList) == ", len(euidList)
            if len(euidList) > 0:
                for euid in euidList:
                    ## DEBUGGING
                    if config['General']["debugLevel"] == '5':
                        print "euid == ", euid
                    if euid != "":
                        splitEuid2 = re.split('=', euid)
                        tx.textLine(" "*33 + "euid: %s" % splitEuid2[1])

        tx.textLine("---------------------")
        tx.textLine("")

        self.PageBreakingAndFooter(canv, tx, title)




    def SendEmail(self, config, title, department, outputfile, emailAddress=""):
        """ use mutt to send pdf attachments to recipients """

        if emailAddress == "":
            emailAddress = raw_input("Email Address of Recipient? ")

        cmd = config['General']["usrBinPath"] + "mutt -a " + outputfile + " -s '" + title + " - " + department + "' " + emailAddress + " < '.'"
        print cmd
        os.system(cmd)
        
    def PageBreakingAndFooter(self, canv, tx, title, verbose=1):
        """ Test for cursor position and insert page break if necessary
            Also, add a footer (page number)
            """
        #page breaking
        y = tx.getY()   #get y coordinate
        if y < self.bottom_margin + 1*inch:
            canv.drawText(tx)
            canv.showPage()
            self.DrawPageFrame(canv, title)
            canv.setFont('Times-Roman', 12)
            tx = canv.beginText(self.left_margin, self.top_margin - 0.5*inch)

            #page
            pg = canv.getPageNumber()
            if verbose and pg % 10 == 0:
                print 'formatted page %d' % canv.getPageNumber()

        return tx

    



if __name__=='__main__':
    quiet = ('-q' in sys.argv)
    title = "Web User Report"
    department = "EriKin Web Hosting"
    header = "Virtual Host" + " "*17 + "| User Full Name" + " "*13 + "| User ID "
    data = [["www.erikin.com:", ["test user", "tuser"]]]
    outputfile = "/tmp/reportlab.pdf"
    r = ReportFunc()
    r.Run(title, department, header, data, outputfile, verbose=1)

